﻿using System.Collections;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Foundation
{
    /// <summary>
    /// Selectable item control for combo box.
    /// </summary>
    public class SelectableItem : UserControl
    {
        private bool _disableCollectionChangeEvent;

        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
            "IsSelected", typeof (bool), typeof (SelectableItem), new PropertyMetadata(IsSelectedChanged));

        public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(
            "SelectedItems", typeof (INotifyCollectionChanged), typeof (SelectableItem),
            new PropertyMetadata(SelectedItemsChanged));

        /// <summary>
        /// Initializes a new instance of the <see cref="SelectableItem"/> class.
        /// </summary>
        public SelectableItem()
        {
            LayoutUpdated += (o, e) => UpdateState(this);
            MouseUp += (o, e) => { e.Handled = true; };
            MouseDown += (o, e) =>
                {
                    e.Handled = true;
                    if (e.LeftButton == MouseButtonState.Pressed)
                    {
                        IsSelected = !IsSelected;
                    }
                };
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is selected.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is selected; otherwise, <c>false</c>.
        /// </value>
        public bool IsSelected
        {
            get { return (bool) GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        /// <summary>
        /// Gets or sets the selected items.
        /// </summary>
        /// <value>
        /// The selected items.
        /// </value>
        public INotifyCollectionChanged SelectedItems
        {
            get { return (INotifyCollectionChanged) GetValue(SelectedItemsProperty); }
            set { SetValue(SelectedItemsProperty, value); }
        }

        private IList SelectedItemsAsList
        {
            get { return SelectedItems as IList; }
        }

        private static void IsSelectedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            var @this = (SelectableItem) dependencyObject;
            if (@this._disableCollectionChangeEvent || @this.DataContext == null)
            {
                return;
            }

            if ((bool) args.NewValue)
            {
                @this.SelectedItemsAsList.Add(@this.DataContext);
            }
            else
            {
                @this.SelectedItemsAsList.Remove(@this.DataContext);
            }
        }

        private static void SelectedItemsChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            var @this = (SelectableItem) dependencyObject;
            var collection = args.NewValue as INotifyCollectionChanged;

            if (collection != null)
            {
                collection.CollectionChanged += (o, e) => UpdateState(@this);
            }
        }

        private static void UpdateState(SelectableItem selectableItem)
        {
            selectableItem._disableCollectionChangeEvent = true;

            if (selectableItem.SelectedItemsAsList != null)
            {
                selectableItem.IsSelected = selectableItem.SelectedItemsAsList.Contains(selectableItem.DataContext);
            }

            selectableItem._disableCollectionChangeEvent = false;
        }
    }
}
